home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part2 / 11847 < prev    next >
Encoding:
Text File  |  1996-08-05  |  5.1 KB  |  144 lines

  1. Path: ix.netcom.com!netnews
  2. From: jlilley@ix.netcom.com (John Lilley)
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: For Experts: How to load a DLL dynamically ?
  5. Date: 16 Mar 1996 16:35:30 GMT
  6. Organization: Netcom
  7. Message-ID: <4ieqki$dqv@cloner3.netcom.com>
  8. References: <4ibr0a$8f9@nms.telepost.no>
  9. NNTP-Posting-Host: den-co12-24.ix.netcom.com
  10. Mime-Version: 1.0
  11. Content-Type: Text/Plain; charset=US-ASCII
  12. X-NETCOM-Date: Sat Mar 16  8:35:30 AM PST 1996
  13. X-Newsreader: WinVN 0.99.7
  14.  
  15. In article <4ibr0a$8f9@nms.telepost.no>, ca@sesam.dnv.no says...
  16. >
  17. >Hi everyone,
  18. >
  19. >I have a problem which I'm sure some of you experts can solve (???):
  20. >I'm using MSVC++ 4.0 under Windows NT 3.51.
  21. >
  22. >But what do I do if I have a DLL which export classes ? i.e.
  23. >
  24. >#ifdef DLL_IMPLEMENTATION
  25. >   #define IMPORT_EXPORT _declspec(dllexport)
  26. >#else
  27. >   #define IMPORT_EXPORT _declspec(dllimport)
  28. >#endif
  29. >
  30. >class IMPORT_EXPORT DLLfoo {   // class exported from dll
  31. >public:
  32. >   DLLfoo();                   // constructor
  33. >   int bar();                  // some member function
  34. >private:
  35. >   int value;
  36. >};
  37. >
  38. >In an application using the DLL, I want to:
  39. >
  40. >   DLLfoo foo;                 // create object from DLL class DLLfoo
  41. >   int somevalue = foo.bar();  // call member function of that class
  42.  
  43.  
  44. Funny you should ask, I just did this yesterday...
  45.  
  46. There are several levels to the problem.  Note that this only applies to
  47. what you want to do, which is dynamic loading and binding.  Static
  48. binding of DLLs is easy.
  49.  
  50. The first problem is that since the methods are loaded at runtime, you
  51. can never create and destroy an object of this class!  At least not 
  52. directly.  In other words, you could not write:
  53.     DLLfoo f;
  54. because the constructor for foo is unavailable, AND you're not allowed
  55. to call it explicitly.  So I would write a static member to create and destroy
  56. DLLfoos.  Note that limits the use of foo to heap allocation, but that is 
  57. necessary because there is no dynamic loading of the constructor of the class.
  58. So change class DLLfoo.  I'd remove the class export, because it does you 
  59. no good anyway, and just export the create/destroy methods.
  60.  
  61. #define EXPORT __declspec(dllexport)
  62. class DLLfoo {
  63.    static EXPORT DLLfoo* Create(/*args*/);      // create a foo
  64.    static EXPORT void Destroy(DLLfoo* foo);     // destroy a foo
  65.     ...
  66. };
  67.  
  68.  
  69. Which brings us to the second problem:  How do you get ahold of the static methods?
  70. C++ methods are "decorated" or name-mangled, which means that you cannot just use
  71. "Create" and "Destroy" as the names passed to GetProcAddress().  Instead you need
  72. to use the decorated name, which look more like "?Create@DLLfoo@@SAPAV1@PAVDLLfoo@@@Z".
  73. To find the actual mangled names, compile the DLL and run DUMPBIN on it, and use
  74. the names that seem like the right ones.  This is the other reason to only export
  75. the Create and Destroy methods, to avoid sifting over a zillion names in the
  76. DUMPBIN output.
  77.  
  78.  
  79. Now you can load the library and create a DLLfoo:
  80.    typedef DLLfoo* (*CreateFooFP)(/*args*/);
  81.    HINSTANCE hinstance = LoadLibrary("foo.dll");
  82.    CreateFooFP createFoo = (CreateFooFP)GetProcAddress("MANGLED_NAME_GOES_HERE");
  83.    DLLfoo* foo = createFoo(/*args*/);
  84.  
  85. Note that you can substitute a function pointer for a method in this case
  86. only because the method is static.  I'm not sure if this is "official" but
  87. it works.
  88.  
  89. Now you've got a foo but can't DO anything with it, because you haven't imported the
  90. other methods.  You could use the DUMPBIN procedure to get the mangled names for
  91. other methods, but I would use the following trick instead:  Make all of the
  92. methods you want to use "virtual".  This automatically binds them at runtime
  93. via the object vtable, so you don't need to load them or call them through a
  94. "pointer-to-object-method", which is ugly.  You don't even need to export them.
  95. So your complete DLLfoo should be something like:
  96.  
  97. // header
  98. #define EXPORT __declspec(dllexport)
  99. class DLLfoo {
  100. public:
  101.    static EXPORT DLLfoo* Create(/*args*/);      // create a foo
  102.    static EXPORT void Destroy(DLLfoo* foo);     // destroy a foo
  103.     // all public methods are virtual
  104.    virtual void method1(/*args*/);
  105.    virtual int method2(/*args*/);
  106.    ...
  107. private:
  108.    // private methods can be non-virtual
  109. };
  110.  
  111. // source
  112. DLLfoo* DLLfoo::Create(/*args*/) { return new DLLfoo(/*args*/); }
  113. void DLLfoo::Destroy(DLLfoo*foo) { delete foo; }
  114. void DLLfoo::method1(/*args*/) { ... }
  115. int DLLfoo::method2(/*args*/) { ... }
  116.  
  117.  
  118. Of course, you *still* cannot:
  119.    1) Create a DLLfoo on the stack
  120.    2) Copy a DLLfoo using a copy constructor or assignment operator.
  121.    3) Call new or delete directly on the class.
  122.  
  123. All of this can prohibit it's use in container classes.
  124. If you need that, then create a "proxy" class on the application side
  125. that wrappers DLLfoo, creates a DLLfoo inside its constructor, etc:
  126.  
  127. class AppFoo {
  128. public:
  129.    AppFoo() { dllfoo = dllFooCreateFuncPtr(...); }
  130.    ~AppFoo() { dllFooDestroyFuncPtr(dllfoo); }
  131.    void method1(/*args*/) { doofoo->method1(/*args*/); }
  132.    int method2(/*args*/) { return doofoo->method2(/*args*/); }
  133. private:
  134.    DLLfoo* dllfoo;
  135. }
  136.  
  137.  
  138. Hope it helps.  This is a nasty one but the solution is so (relatively) simple!
  139.  
  140. john lilley
  141.  
  142.     
  143.  
  144.